#include "brdf_phong.h"

namespace gemren
{
	
	err_t brdf_phong::set_my_string(std::string& name, const std::string& value)
	{
		//todo conserve energy
		float kscoef = 2*PI/(ns+2);
		
		//conservation of energy:
		// PI* Kd + 2*PI/(Ns+2) * Ks <=1
		// Kd is divided by PI in brdf_diffuse::bounce
		
		
		if(name == "Ks")  
		{
			//it's "ks", not "rho_s"
			display_ks = spectrum_dynamic(value, 0, 1.0f/kscoef);
			ks.copy_from_spectrum(display_ks);

			//keep energy
			display_color.limit(color_s(1.0f) + (-kscoef * ks)); 
			color.copy_from_spectrum(display_color);

		}
		else if(name == "Kd")
		{
			//color "rho_d", not "Kd"
			display_color = spectrum_dynamic(value, 0, 1);
			color.copy_from_spectrum(display_color);

			display_ks.limit( 1.0f/kscoef*(color_s(1.0f) + -1.0f*color));
			ks.copy_from_spectrum(display_ks);
		}
		else return ERR_BAD_PROP;

		float ksm = ks.max();
		ratio = ksm / (ksm + color.max());
		return ERR_OK;
	}
	
	err_t brdf_phong::set_my_float(std::string& name, const float value)
	{
		if(name== "Ns")
		{
			ns = (value > 0.0f?value:0.0f);
			float kscoef = 2*PI/(ns+2);
			display_ks.limit(color_s(1.0f/kscoef));
			ks.copy_from_spectrum(display_ks);

			display_color.limit(color_s(1.0f) + (-kscoef * ks)); 
			color.copy_from_spectrum(display_color);
			return ERR_OK;
		}
		else return ERR_BAD_PROP;
	}
	void brdf_phong::announce_properties(const std::string& prefix, property_announcer announcer)
	{
		//brdf_diffuse::announce_properties(prefix, announcer);
		announcer((prefix+".Ks").c_str(), ANNOUNCED_STRING, val_to_str(display_ks).c_str());
		announcer((prefix+".Kd").c_str(), ANNOUNCED_STRING, val_to_str(display_color).c_str());
		announcer((prefix+".Ns").c_str(), ANNOUNCED_FLOAT, val_to_str(ns).c_str());

	}
	void brdf_phong::bounce(random* ran, const scene* sc, intersection* i)const
	{
		if(ran->getf() > ratio)
		{//diffuse
			brdf_diffuse::bounce(ran, sc, i);
			i->dim_light(1.0f/(1.0f-ratio));
		}
		else
		{//glossy
			float cos;
			//do
				i->outcoming = ran->cosn_lobe(i->incoming - (2* embree::dot(i->normal, i->incoming))*i->normal, ns);
			if((cos = embree::dot(i->normal, i->outcoming))<0.0f)
				i->terminate();
			else
			{
				i->dim_light((cos/ratio) *ks);
				i->reflectance = ks.max();
			}
		}
	}
	void brdf_phong::bounce_fast(random* ran, const scene* sc, intersection* i)const
	{
		brdf_diffuse::bounce_fast(ran, sc, i);
	}
	float brdf_phong::pdf(const coord& incoming, const coord& outcoming, const coord& normal)
	{
		coord mirror = -incoming+ 2*embree::dot(incoming, normal)*normal;
		float cosn = std::pow(embree::dot(mirror, outcoming), ns);
		return 
			(1.0f-ratio)*brdf_diffuse::pdf(incoming, outcoming, normal)
			+
			(ratio)* (ns+2)/(2*PI)*cosn;
	}

	color_s brdf_phong::throughput(const coord& from, const coord& to, const coord& normal)const
	{
		coord mirror = -to + 2*embree::dot(to, normal)*normal;
		float cosn = std::pow(embree::dot(mirror, from), ns);
		return 
			brdf_diffuse::throughput(from, to, normal)
			+ 
			ks*(cosn)*embree::dot(from, normal);
	}
}